package com.shiva.oms.logview.api.control;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextPane;
import javax.swing.JTree;
import javax.swing.RowFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableRowSorter;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eltima.components.ui.DatePicker;
import com.sf.shiva.oms.common.constant.LogTableConstant;
import com.sf.shiva.oms.common.util.CollectionUtil;
import com.sf.shiva.oms.common.util.DateUtil;
import com.sf.shiva.oms.common.util.ExceptionUtils;
import com.shiva.oms.biz.HistoryConnRecordBiz;
import com.shiva.oms.biz.HistoryFileRecordBiz;
import com.shiva.oms.logview.api.model.LogDataTableModel;
import com.shiva.oms.logview.api.model.LogFileDirTreeModel;
import com.shiva.oms.logview.domain.ConnectCfg;
import com.shiva.oms.logview.domain.HistoryFileRecord;
import com.shiva.oms.logview.domain.LogData;
import com.shiva.oms.logview.domain.LogParseCfg;
import com.shiva.oms.logview.domain.QueryCond;
import com.shiva.oms.logview.util.SshTransferHelper;
import com.shiva.oms.server.LogViewerParserService;

/**
 * 
 * 主界面的控制逻辑层
 * 
 * <pre>
 * HISTORY
 * ****************************************************************************
 *  ID    DATE            PERSON            REASON
 *  1     2018年4月18日         LA.01367604           Create
 * ****************************************************************************
 * </pre>
 * 
 * @author LA.01367604
 * @version 1.0
 */
public class MainFrameControl {

    private static final Logger logger = LoggerFactory.getLogger(MainFrameControl.class);

    private LogViewerParserService service = new LogViewerParserService();
    private SshTransferHelper sshConn;
    private ConnectCfg connectCfg;
    private LogParseCfg logParseCfg = new LogParseCfg();
    private List<LogData> list = new ArrayList<>();

    private Properties parseProperties;
    private String[] headerNames = new String[] { "ID", "日期时间", "级别", "类名", "方法名", "详细信息" };
    private String countLabelStrFormat = "共 %d条";
    private HistoryFileRecordBiz historyFileRecordBiz = HistoryFileRecordBiz.getInstance();
    private HistoryConnRecordBiz historyConnRecordBiz = HistoryConnRecordBiz.getInstance();
    private String selectedFileName = "日志文件";
    private String detailFormat = "    id :%s\n" + "   date :%s\n" + "  level:%s\n"
            + "  line :%s\n" + "   ndc :%s\n" + " thread:%s\n" + " clazz :%s\n" + "method :%s\n"
            + "message:%s";
    private final String HighColorText = "orderNo";

    /**
     * 设置日期控件的初始配置
     * 
     * @param datepick
     * @author LA.01367604-2018年5月5日
     */
    public void setDateTimePicker(DatePicker datepick) {
        // int[] hilightDays = { 1, 3, 5, 7 };
        // int[] disabledDays = { 4, 6, 5, 9 };
        //
        // datepick.setHightlightdays(hilightDays, Color.red);//
        // 设置一个月份中需要高亮显示的日子
        // datepick.setDisableddays(disabledDays);// 设置一个月份中不需要的日子，呈灰色显示
        // datepick.setLocale(Locale.CHINA);// 设置国家
        datepick.setTimePanleVisible(true);// 设置时钟面板可见
    }

    /**
     * @wbp.parser.entryPoint
     */
    public void createTableFilter(JTable table, int filterColomnIndex, String filterValue) {
        TableRowSorter<LogDataTableModel> sorter = new TableRowSorter<>(
                (LogDataTableModel) table.getModel());
        if (StringUtils.isEmpty(filterValue)) {
            sorter.setRowFilter(null);
        } else {
            RowFilter<LogDataTableModel, Object> regexFilter = RowFilter.regexFilter(filterValue,
                filterColomnIndex);
            sorter.setRowFilter(regexFilter);
        }
        table.setRowSorter(sorter);
    }

    /**
     * 创建打开文件记录历史的子菜单项
     * 
     * @param hisFilesMenu
     * @param tree
     * @param root
     * @author LA.01367604-2018年5月5日
     * @wbp.parser.entryPoint
     */
    public void createHisFilesMenuItem(JPanel panel, JMenu hisFilesMenu, JTree tree, DefaultMutableTreeNode root) {
        List<HistoryFileRecord> filesList = historyFileRecordBiz.getList();
        Collections.reverse(filesList); // 倒序排列
        if (filesList.isEmpty()) {
            JMenuItem item = new JMenuItem("<空>");
            hisFilesMenu.add(item);
        } else {
            for (HistoryFileRecord rec : filesList) {
                JMenuItem item = new JMenuItem(rec.getFileName());
                item.addMouseListener(new MouseAdapter() {

                    @Override
                    public void mousePressed(MouseEvent e) {
                        selectedFileName = rec.getFileName();
                        createFilesTreeNode(rec.toFile(), tree, root);
                        panel.repaint();
                    }
                });
                hisFilesMenu.add(item);
            }
        }
    }

    /**
     * 创建打开文件记录历史的子菜单项
     * 
     * @param hisConnMenu
     * @param tree
     * @param root
     * @author LA.01367604-2018年5月5日
     */
    public void createHisConnMenuItem(JPanel panel, JMenu hisConnMenu, JTree tree, DefaultMutableTreeNode root) {
        List<ConnectCfg> connList = historyConnRecordBiz.getList();
        Collections.reverse(connList); // 倒序排列
        if (connList.isEmpty()) {
            JMenuItem item = new JMenuItem("<空>");
            hisConnMenu.add(item);
        } else {
            for (ConnectCfg rec : connList) {
                JMenuItem item = new JMenuItem(rec.getCfgName());
                item.addMouseListener(new MouseAdapter() {

                    @Override
                    public void mousePressed(MouseEvent e) {
                        connectCfg = rec;
                        connectAndGetLogFiles(panel, rec, tree, root);
                    }
                });
                hisConnMenu.add(item);
            }
        }
    }

    /**
     * 创建列表tree 单个文件节点
     * 
     * @param file
     * @param tree
     * @param root
     * @author LA.01367604-2018年5月5日
     */
    public void createFilesTreeNode(File file, JTree tree, DefaultMutableTreeNode root) {
        root.add(new DefaultMutableTreeNode(new LogFileDirTreeModel(file)));
        tree.setModel(new DefaultTreeModel(root));
    }

    /**
     * 创建列表tree 多节点，文件目录和目录下的全部文件
     * 
     * @param fileDir
     * @param files
     * @param tree
     * @param root
     * @author LA.01367604-2018年5月5日
     */
    public void createFilesTreeNode(File fileDir, File[] files, JTree tree, DefaultMutableTreeNode root) {
        DefaultMutableTreeNode dirNode = new DefaultMutableTreeNode(new LogFileDirTreeModel(fileDir));
        if (files.length==0){
            DefaultMutableTreeNode node = new DefaultMutableTreeNode("Null");
            dirNode.add(node);
        } else {
            for (int i = 0; i < files.length; i++) {
                if (files[i].isFile()) {
                    DefaultMutableTreeNode node = new DefaultMutableTreeNode(new LogFileDirTreeModel(files[i]));
                    dirNode.add(node);
                }
            }
        }
        root.add(dirNode);
        tree.setModel(new DefaultTreeModel(root));
    }

    /**
     * 创建列表tree 多节点，文件目录和目录下的全部文件
     * 
     * @param fileDir
     * @param fileNames
     * @param tree
     * @param root
     * @author LA.01367604-2018年5月5日
     */
    private void createFilesTreeNode(File fileDir, String[] fileNames, JTree tree, DefaultMutableTreeNode root) {
        DefaultMutableTreeNode dirNode = new DefaultMutableTreeNode(new LogFileDirTreeModel(fileDir));
        if (fileNames.length==0){
            DefaultMutableTreeNode node = new DefaultMutableTreeNode("Null");
            dirNode.add(node);
        } else {
            for (int i = 0; i < fileNames.length; i++) {
                DefaultMutableTreeNode node = new DefaultMutableTreeNode(new LogFileDirTreeModel(fileNames[i]));
                dirNode.add(node);
            }
        }
        root.add(dirNode);
        tree.setModel(new DefaultTreeModel(root));
    }

    /**
     * 创建下拉菜单
     * 
     * @param loadItem
     * @return
     * @author LA.01367604-2018年5月5日
     */
    public JPopupMenu createPopMenu(JMenuItem... loadItem) {
        JPopupMenu popupmenu = new JPopupMenu();
        for (int i = 0; i < loadItem.length; i++) {
            popupmenu.add(loadItem[i]);
        }
        return popupmenu;
    }
    // /**
    // * 动态创建日志分类的过滤项checkbox
    // */
    // private void createCheckBox() {
    // Rectangle labelLocation = filterLabel.getBounds();
    // int count1 = 0;
    // int interval = 15;
    // for (Map.Entry<String, Integer> entry : categoryNames.entrySet()) {
    // if (++count1 <= 5) {
    // JCheckBox checkBox = new JCheckBox(entry.getKey());
    // checkBox.setSelected(true);
    // labelLocation.x = (labelLocation.x + labelLocation.width + interval);
    // labelLocation.width = 200;
    // checkBox.setBounds(labelLocation);
    // panel.add(checkBox);
    // }
    // }
    // }

    /**
     * 根据日志级别过滤（checkbox）
     * 
     * @author LA.01367604-2018年4月18日
     */
    public List<LogData> filterByLevel(List<LogData> tablelist, List<String> selectedLevel) {
        if (CollectionUtil.isEmpty(tablelist)) {
            return new ArrayList<>();
        }
        return service.filterByLevel(tablelist, selectedLevel);
    }

    public List<LogData> filterByClazz(JTable table, String clazzName) {
        List<LogData> showList = getTableDatas(table);
        if (CollectionUtil.isEmpty(showList)) {
            return new ArrayList<>();
        }
        return service.filterByClass(showList, clazzName);
    }

    public List<LogData> filterByKeyword(JTable table, String keyword) {
        List<LogData> showList = getTableDatas(table);
        if (CollectionUtil.isEmpty(showList)) {
            return new ArrayList<>();
        }
        return service.filterByKeyword(showList, keyword);
    }

    public List<LogData> filterByTime(JTable table, Date startTime, Date endTime) {
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        if (this.parseProperties != null
                && null != this.parseProperties.get(LogTableConstant.PARSING_PROPERTY_DATE_FORMAT)) {
            String dateFormat = (String) this.parseProperties.get(LogTableConstant.PARSING_PROPERTY_DATE_FORMAT);
            String startDateStr = DateUtil.formatDate(startTime, dateFormat);
            startTime = DateUtil.parse(startDateStr, dateFormat);
            String enDateStr = DateUtil.formatDate(endTime, dateFormat);
            endTime = DateUtil.parse(enDateStr, dateFormat);
        } else {
            logger.warn("未找到解析配置，使用默认日期格式解析");
        }
        return service.filterByTime(list, startTime, endTime);
    }

    /**
     * 开始解析日志文件，包括本地文件和远程读取的文件
     * 
     * @author LA.01367604-2018年5月4日
     */
    public void startParseLogFile(LogFileDirTreeModel selectedFileNode) {
        if (service.isParsingInProgress()) {
            System.out.println("正在解析文件，请稍后再试");
            return;
        }
        System.out.println("解析文件：" + selectedFileNode.getNodeName());
        try {
            if (selectedFileNode.getFile() != null) {
                InputStream input = new FileInputStream(selectedFileNode.getFile());
                fillLogData(input);
                historyFileRecordBiz.addFileRec(new HistoryFileRecord(selectedFileNode.getFile().getParent(), selectedFileNode.getFile().getName()));
            } else {
                InputStream input = sshConn.getFileContent(connectCfg.getFileDir(), selectedFileNode.getNodeName());
                fillLogData(input);
            }
        } catch (Exception e1) {
            logger.error("解析失败（{}）--{}",selectedFileNode.getNodeName(),ExceptionUtils.extractStackTrace(e1));
        }
    }

    /**
     * 解析日志文件，保存解析到的全部列表数据
     * 
     * @param patternName
     * @param input
     * @author LA.01367604-2018年4月18日
     * @throws Exception
     */
    private void fillLogData(InputStream input) throws Exception {
        list.clear();
        list = service.parse(input);
        // categoryNames = service.getCategoryNames();
        parseProperties = service.getProperties();
    }

    public List<LogData> getTableDatas(JTable table) {
        LogDataTableModel tableModel = (LogDataTableModel) table.getModel();
        return tableModel.getDatas();
    }

    public void fillLogDetailText(JTextPane textPane, JTable table, int index, QueryCond queryCond) {
        LogData data = getTableDatas(table).get(index);
        String dateStr = "";
        if (this.parseProperties != null && null != this.parseProperties.get(LogTableConstant.PARSING_PROPERTY_DATE_FORMAT)) {
            String dateFormat = (String) this.parseProperties.get(LogTableConstant.PARSING_PROPERTY_DATE_FORMAT);
            dateStr = DateUtil.formatDate(data.getDate(), dateFormat);
        }
        if (StringUtils.isEmpty(dateStr)) {
            dateStr = DateUtil.date2String(data.getDate());
        }
        String content = String.format(detailFormat, data.getId(), dateStr, data.getLevel().toString(), data.getLine(), data.getNdc(), data.getThread(), data.getClazz(), data.getMethod(), data.getMessage());
        textPane.setText(content);
        List<String> words = new ArrayList<>();
        // words.add(HighColorText);
        if (queryCond != null && StringUtils.isNotEmpty(queryCond.getKeyword())) {
            words.add(queryCond.getKeyword());
        }
        SimpleAttributeSet wordAttr = new SimpleAttributeSet();
        StyleConstants.setForeground(wordAttr, Color.red);
        StyleConstants.setBackground(wordAttr, Color.yellow);
        try {
            setStyleText(textPane, wordAttr, words);
        } catch (BadLocationException e) {
            logger.error("设置关键字字体格式失败--{}", ExceptionUtils.extractStackTrace(e));
        }
    }

    /**
     * 设置指定的字符串不同的字体颜色等属性
     * 
     * @param textPane
     * @param wordAttr
     * @param words
     * @author LA.01367604-2018年5月4日
     * @throws BadLocationException
     */
    public void setStyleText(JTextPane textPane, SimpleAttributeSet wordAttr, List<String> words)
            throws BadLocationException {
        StyledDocument doc = textPane.getStyledDocument();
        String content = doc.getText(0, doc.getLength());
        if (StringUtils.isEmpty(content)) {
            return;
        }
        for (String word : words) {
            int index = 0;
            while ((index = content.indexOf(word, index)) >= 0) {
                doc.setCharacterAttributes(index, word.length(), wordAttr, true);
                index = index + word.length();
            }
        }
    }

    /**
     * 设置对话框初始显示在窗口中间位置
     * 
     * @param frame
     * @param dialog
     * @author LA.01367604-2018年5月5日
     */
    public void setDialogMidLocation(JFrame frame, JDialog dialog) {
        int parentWidth = frame.getWidth();
        int parentHight = frame.getHeight();
        dialog.setLocation(frame.getX() + parentWidth / 2 - dialog.getWidth() / 2, frame.getY()
                + parentHight / 2 - dialog.getHeight() / 2);// 设置窗口居中显示
    }

    /**
     * list对象集合转数组表格数据
     * 
     * @param list
     * @return
     * @author LA.01367604-2018年4月17日
     */
    public Object[][] getArrayFromList(List<LogData> list) {
        int maxData = list.size();
        Object[][] data = new Object[maxData][headerNames.length];
        for (int i = 0; i < list.size(); i++) {
            LogData model = list.get(i);
            data[i][0] = model.getId();
            data[i][1] = model.getDate();
            data[i][2] = model.getLevel();
            data[i][3] = model.getClazz();
            data[i][4] = model.getMethod();
            data[i][5] = model.getMessage();
        }
        return data;
    }

    /**
     * 连接登录服务器，获取指定路径下的文件列表，并创建列表tree
     * 
     * @param connectCfg
     * @param tree
     * @param root
     * @author LA.01367604-2018年5月5日
     */
    public void connectAndGetLogFiles(JPanel panel, ConnectCfg connectCfg, JTree tree, DefaultMutableTreeNode root) {
        if (StringUtils.isNotBlank(connectCfg.getIp()) && StringUtils.isNotBlank(connectCfg.getUser()) && StringUtils.isNotBlank(connectCfg.getPassword())) {
            this.connectCfg = connectCfg;
            sshConn = new SshTransferHelper(connectCfg.getIp(), connectCfg.getUser(), connectCfg.getPassword());
            // InputStream is = sshConn.getFileContent(connectCfg.getFileDir() + fileName);
            if (sshConn.isConnected()){
                List<String> files = sshConn.getFileNamesFromDir(connectCfg.getFileDir());
                if (files != null) {
                    if (files.isEmpty()){
                        JOptionPane.showMessageDialog(panel, "当前目录无法获取文件！", "获取文件", JOptionPane.WARNING_MESSAGE);
                    } else {
                        historyConnRecordBiz.addFileRec(connectCfg);
                    }
                    createFilesTreeNode(new File(connectCfg.getFileDir()), files.toArray(new String[files.size()]), tree, root);
                }
            } else {
                JOptionPane.showMessageDialog(panel, "登录失败", "连接登录", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    /**
     * 设置表格的某一行的背景色
     * 
     * @param table
     */
    public void setOneRowBackgroundColor(JTable table, Color color) {

        try {
            DefaultTableCellRenderer tcr = new DefaultTableCellRenderer() {

                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                    LogDataTableModel tableModel = (LogDataTableModel) table.getModel();
                    if (tableModel.getRow(row).isMarked()) {
                        setBackground(color);
                        setForeground(Color.WHITE);
                    } else {
                        setBackground(Color.WHITE);
                        setForeground(Color.black);
                    }
                    return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                }
            };
            table.setDefaultRenderer(Object.class, tcr);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public ConnectCfg getConnectCfg() {
        return connectCfg;
    }

    public void setConnectCfg(ConnectCfg connectCfg) {
        this.connectCfg = connectCfg;
    }

    public LogParseCfg getLogParseCfg() {
        return logParseCfg;
    }

    public void setLogParseCfg(LogParseCfg logParseCfg) {
        this.logParseCfg = logParseCfg;
    }

    public List<LogData> getList() {
        return list;
    }

    public void setList(List<LogData> list) {
        this.list = list;
    }

    public Properties getParseProperties() {
        return parseProperties;
    }

    public void setParseProperties(Properties parseProperties) {
        this.parseProperties = parseProperties;
    }

    public String getSelectedFileName() {
        return selectedFileName;
    }

    public void setSelectedFileName(String selectedFileName) {
        this.selectedFileName = selectedFileName;
    }

    public String[] getHeaderNames() {
        return headerNames;
    }

    public void setHeaderNames(String[] headerNames) {
        this.headerNames = headerNames;
    }

    public String getCountLabelStrFormat() {
        return countLabelStrFormat;
    }

    public void setCountLabelStrFormat(String countLabelStrFormat) {
        this.countLabelStrFormat = countLabelStrFormat;
    }

    public HistoryFileRecordBiz getHistoryFileRecordBiz() {
        return historyFileRecordBiz;
    }

    public void setHistoryFileRecordBiz(HistoryFileRecordBiz historyFileRecordBiz) {
        this.historyFileRecordBiz = historyFileRecordBiz;
    }

    public HistoryConnRecordBiz getHistoryConnRecordBiz() {
        return historyConnRecordBiz;
    }

    public void setHistoryConnRecordBiz(HistoryConnRecordBiz historyConnRecordBiz) {
        this.historyConnRecordBiz = historyConnRecordBiz;
    }

    public String getDetailFormat() {
        return detailFormat;
    }

    public void setDetailFormat(String detailFormat) {
        this.detailFormat = detailFormat;
    }

    public String getHighColorText() {
        return HighColorText;
    }

    public boolean isParsingInProgress() {
        return service.isParsingInProgress();
    }
}
